using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Acms.SqlDal;

namespace Acms.Bll
{
    public class Email : BaseItem
    {
        protected Email() : base() { }
        protected Email(Hashtable table) : base(table) { }
        protected Email(Hashtable table, List<Email> collection) : base(table, collection) { }


        protected override Acms.SqlDal.Base CreateDal()
        {
            return new Acms.SqlDal.EmailDal();
        }

        public static Email CreateInstance(User user, string overrideEmailAddress, string filePath)
        {
            Email tmp = new Email();
            tmp.Created = DateTime.Now;
            tmp.UserId = user.Id;
            tmp.user = user;
            tmp.FilePath = filePath;
            tmp.EmailAddress = overrideEmailAddress;
            tmp.CreateEmail();
            return tmp;
        }

        public static Email CreateInstance(User user, string filePath)
        {
            Email tmp = new Email();
            tmp.Created = DateTime.Now;
            tmp.UserId = user.Id;
            tmp.user = user;
            tmp.FilePath = filePath;
            tmp.CreateEmail();
            return tmp;
        }

        public static Email CreateInstance(string name, string emailAddress, string filePath)
        {
            Email tmp = new Email();
            tmp.Created = DateTime.Now;
            tmp.Name = name;
            tmp.EmailAddress = emailAddress;
            tmp.FilePath = filePath;
            tmp.CreateEmail();
            return tmp;
        }

        public new void Update()
        {
            base.Update();
        }

        protected override object SaveChanges(ref object concurencyId, Acms.SqlDal.Base dal)
        {
            int idOut = Id;
            ((SqlDal.EmailDal)dal).Update(ref idOut, UserId, Name, EmailAddress, FilePath, To, Subject, Body, Bcc, Cc, From, ReplyTo, Html, Created, Sent, Failed, ref concurencyId);
            Id = idOut;
            return Id;
        }

        private void LoadXmlDocument()
        {
            System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
            xmlDocument.Load(FilePath);
            if (xmlDocument != null)
            {
                System.Xml.XmlNode subjectNode = xmlDocument.DocumentElement.SelectSingleNode("subject");
                if (subjectNode != null)
                {
                    Subject = subjectNode.InnerText;
                }

                System.Xml.XmlNode bodyNode = xmlDocument.DocumentElement.SelectSingleNode("body");
                if (bodyNode != null)
                {
                    Body = bodyNode.InnerText;
                }

                System.Xml.XmlNode bccNode = xmlDocument.DocumentElement.SelectSingleNode("bcc");
                if (bccNode != null)
                {
                    Bcc = bccNode.InnerText;
                }

                System.Xml.XmlNode formatNode = xmlDocument.DocumentElement.SelectSingleNode("format");
                if (formatNode != null)
                {
                    if (formatNode.InnerText != null && formatNode.InnerText.ToLower() == "html")
                        Html = true;
                    else
                        Html = false;
                }

                System.Xml.XmlNode ccNode = xmlDocument.DocumentElement.SelectSingleNode("cc");
                if (ccNode != null)
                {
                    Cc = ccNode.InnerText;
                }

                System.Xml.XmlNode fromNode = xmlDocument.DocumentElement.SelectSingleNode("from");
                if (fromNode != null)
                {
                    From = fromNode.InnerText;
                    //default Reply to to From to help with any bouncing
                    ReplyTo = From;
                }

                System.Xml.XmlNode replyToNode = xmlDocument.DocumentElement.SelectSingleNode("replyTo");
                if (replyToNode != null)
                {
                    ReplyTo = replyToNode.InnerText;
                }
            }
        }

        private void CreateEmail()
        {
            LoadXmlDocument();
            if (user != null)
            {
                Format("UserName", user.UserName);
                Format("Address1", user.Address1);
                Format("Address2", user.Address2);
                Format("LongCreated", user.Created.ToLongDateString());
                Format("ShortCreated", user.Created.ToShortDateString());

                if (user.DateOfBirth == null)
                {
                    Format("LongDateOfBirth", "");
                    Format("ShortDateOfBirth", "");
                }
                else
                {
                    Format("LongDateOfBirth", user.DateOfBirth.Value.ToLongDateString());
                    Format("ShortDateOfBirth", user.DateOfBirth.Value.ToShortDateString());
                }
                Format("DisplayName", user.DisplayName);
                Format("EmailAddress", user.EmailAddress);
                Format("FirstName", user.FirstName);
                Format("Gender", user.Gender.ToString());
                Format("LastName", user.LastName);
                Format("MobileTel", user.MobileTel);
                Format("PostCode", user.PostCode);
                Format("Town", user.Town);
                Format("UserName", user.UserName);
                foreach (UserCustomProperty prop in user.CustomProperties)
                {
                    Format(prop.Name, prop.Value);
                }

            }
            FormatSiteDetails();
        }

        protected override void Load(Hashtable table)
        {
            Id = (int)table[SqlDal.EmailDal.Fields.Id];
            UserId = (int?)table[SqlDal.EmailDal.Fields.UserId];
            Name = (string)table[SqlDal.EmailDal.Fields.Name];
            EmailAddress = (string)table[SqlDal.EmailDal.Fields.EmailAddress];
            FilePath = (string)table[SqlDal.EmailDal.Fields.FilePath];
            To = (string)table[SqlDal.EmailDal.Fields.To];
            Subject = (string)table[SqlDal.EmailDal.Fields.Subject];
            Body = (string)table[SqlDal.EmailDal.Fields.Body];
            Bcc = (string)table[SqlDal.EmailDal.Fields.Bcc];
            Cc = (string)table[SqlDal.EmailDal.Fields.CC];
            From = (string)table[SqlDal.EmailDal.Fields.From];
            ReplyTo = (string)table[SqlDal.EmailDal.Fields.ReplyTo];
            Html = (bool)table[SqlDal.EmailDal.Fields.Html];
            Created = (DateTime)table[SqlDal.EmailDal.Fields.Created];
            Sent = (DateTime)table[SqlDal.EmailDal.Fields.Sent];
            Failed = (bool)table[SqlDal.EmailDal.Fields.Failed];
        }

        public int Id{get; private set; }
        public int? UserId{get;private set;}
        public string EmailAddress { get; private set; }
        public string Name { get; private set; }
        public string FilePath{ get; private set; }
        public string To { get; private set; }
        public string Body { get; private set; }
        public string Subject { get; private set; }
        public string Bcc { get; private set; }
        public string Cc { get; private set; }
        public string From { get; private set; }
        public string ReplyTo { get; private set; }
        public bool Html { get; private set; }
        public DateTime Created { get; private set; }
        public DateTime Sent { get; private set; }
        public bool Failed { get; private set; }

        private User user;
        public User User
        {
            get 
            {
                if (user == null && UserId != null && UserId.Value > 0)
                    user = User.GetById(UserId.Value);
                return user; 
            }
        }


	    public void Format(string name, string value)
        {
            string key = string.Format("[[{0}]]", name);
            if(Body.Contains(key))
                Body = Body.Replace(key, value);
            if (Subject.Contains(key))
                Subject = Subject.Replace(key, value);
        }

        public void Send()
        {
            System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();
            if (User != null && string.IsNullOrEmpty(EmailAddress))
            {
                mail.To.Add(new System.Net.Mail.MailAddress(User.EmailAddress, User.DisplayName));
            }
            else if (User != null && !string.IsNullOrEmpty(EmailAddress))
            {
                mail.To.Add(new System.Net.Mail.MailAddress(EmailAddress, User.DisplayName));
            }
            else
            {
                mail.To.Add(new System.Net.Mail.MailAddress(EmailAddress, Name));
            }
            AddAddresses(this.Cc, mail.CC);
            AddAddresses(this.Bcc, mail.Bcc);
            if (!string.IsNullOrEmpty(this.From))
                mail.From = GetAddress(From);
            if (!string.IsNullOrEmpty(this.ReplyTo))
                mail.ReplyTo = GetAddress(From);

            mail.Subject = this.Subject;
            mail.Body = this.Body;

            try
            {
                System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
                client.Send(mail);
                mail.Dispose();
            }
            catch
            {
                Failed = true;
            }

            this.To = string.Concat(mail.To[0].Address, ",", mail.To[0].DisplayName);
            this.Sent = DateTime.Now;
            this.Update();
        }

        private void AddAddresses(string addresses, System.Net.Mail.MailAddressCollection collection)
        {
            if (addresses != null)
            {
                foreach (string address in addresses.Split(';'))
                {
                    collection.Add(GetAddress(address));
                }
            }
        }

        private System.Net.Mail.MailAddress GetAddress(string address)
        {
            if (address.Contains(","))
            {
                string email = address.Substring(0, address.IndexOf(","));
                string displayName = address.Substring(address.IndexOf(",") + 1);
                return new System.Net.Mail.MailAddress(email, displayName);
            }
            else
            {
                return new System.Net.Mail.MailAddress(address);
            }
        }

        /// <summary>
        /// Sends forgotten password email using default location of "~/Emails/ForgottenPasswordEmail.xml"
        /// </summary>
        /// <param name="user"></param>
        /// <param name="password"></param>
        public static void SendForgottenPasswordEmail(User user, string password)
        {
            SendForgottenPasswordEmail(user, password, System.Web.HttpContext.Current.Server.MapPath("~/Emails/ForgottenPasswordEmail.xml"));
        }

        /// <summary>
        /// Sends forgotten email password
        /// </summary>
        /// <param name="user"></param>
        /// <param name="password"></param>
        /// <param name="path"></param>
        public static void SendForgottenPasswordEmail(User user, string password, string path)
        {
            Email tmp = Email.CreateInstance(user, path);
            tmp.Format("Password", password);
            tmp.Send();
        }


        internal static void SendRegisteredEmail(User user, string password)
        {
            if (System.Web.HttpContext.Current != null)
            {
                Email tmp = Email.CreateInstance(user, System.Web.HttpContext.Current.Server.MapPath("~/Emails/RegisteredEmail.xml"));
                tmp.Format("Password", password);
                tmp.Send();
            }
        }

        private void FormatSiteDetails()
        {
            if (System.Web.HttpContext.Current != null)
            {
                Site site = Acms.Bll.Site.GetFromHttpRequest(System.Web.HttpContext.Current.Request);
                if (site != null)
                {
                    Format("SiteUrl", string.Concat("http://", site.Root));
                    Format("SiteAdminUrl", string.Concat("http://", site.Root, "/Acms"));
                    Format("SiteName", site.Name);
                }
            }
        }

        private static Email Get(Hashtable table)
        {
            if (table != null)
            {
                return new Email(table);
            }
            else
            {
                return null;
            }
        }

        private static List<Email> Get(Hashtable[] tables)
        {
            if (tables != null)
            {
                List<Email> tmp = new List<Email>();
                foreach (Hashtable table in tables)
                {
                    tmp.Add(new Email(table, tmp));
                }
                return tmp;
            }
            else
            {
                return null;
            }
        }

        public static List<Email> GetAllByEmailAddressAndFilePath(string emailAddress, string filePath)
        {
            EmailDal dal = new EmailDal();
            return Get(dal.GetAllByEmailAddressAndFilePath(emailAddress, filePath));
        }

        public static List<Email> GetAllByUserIdAndFilePath(int userId, string filePath)
        {
            EmailDal dal = new EmailDal();
            return Get(dal.GetAllByUserIdAndFilePath(userId, filePath));
        }
    }
}
